﻿#region Header

/*
Remote views based on linq
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Reflection;
using InterLinq.Base;
using Sebarf.Core.Interfaces;
using Sebarf.Services.Interfaces;
using Sebarf.Utils.Interfaces;
using Sebastof.Services.Interfaces;
using Utils;

#endregion

namespace Sebastof.ProcessChains.ProcessSteps {
	/// <summary>
	/// This is another processing step.
	/// Here we save away the original data of a transfered object so we can later check what changed.
	/// </summary>
	public class CachedOriginalDataBase<T> : ProcessStep<T> {
		#region Public Properties

		[ServiceRequest]
		public IChangeTrackingCacheService ChangeTrackingCacheService { get; set; }

		[ServiceRequest]
		public IServiceLocatorService ServiceLocatorService { get; set; }

		[ServiceRequest]
		public IObjectHierarchyFlattenerService ObjectHierarchyFlattenerService { get; set; }

		#endregion

		#region Public Methods

		public CachedOriginalDataBase(IServiceLocatorService context, IChangeTrackingCacheService cache) {
			ServiceLocatorService = context;
			ChangeTrackingCacheService = cache;
			ObjectHierarchyFlattenerService = context.GetRegisteredService<IObjectHierarchyFlattenerService>();
		}

		public CachedOriginalDataBase() {
		}

		protected void PrepareForType(Type objecttype) {
			Dictionary<Type, Dictionary<object, Dictionary<string, object>>> cache =
				ChangeTrackingCacheService.GetStoreOfNonSebastofObjectsOriginalData();
			if (typeof(IIdentifiable).IsAssignableFrom(objecttype) && !cache.ContainsKey(objecttype)) {
				cache[objecttype] = new Dictionary<object, Dictionary<string, object>>();
			}
		}

		protected void AddObjectData(object o) {
			if (o is ISebastofApplicationObject) {
				return;
			}
			if (!typeof(IIdentifiable).IsAssignableFrom(o.GetType())) {
				return;
			}
			//TODO: if is interlinqobject check if fields exists, only return if no fields exist.

			Dictionary<Type, Dictionary<object, Dictionary<string, object>>> cache =
				ChangeTrackingCacheService.GetStoreOfNonSebastofObjectsOriginalData();
			Type objecttype = o.GetType();
			if (!objecttype.IsPrimitive && objecttype != typeof(string)) {
				//var oid = GetObjectId(toProcess, m_FieldInfos[objecttype]);
				lock (cache) {
					cache[objecttype][o] = new Dictionary<string, object>();
					foreach (FieldInfo field in m_FieldInfos[objecttype]) {
						object val = field.GetValue(o);
						try {
							cache[objecttype][o][field.Name] = val;
						}
						catch {
							throw;
						}
					}
				}
			}
		}

		#endregion

		#region Private Fields

		protected Dictionary<Type, List<FieldInfo>> m_FieldInfos = new Dictionary<Type, List<FieldInfo>>();

		#endregion
	}
}